/*********************************************************************************
 * Software License Agreement (BSD License)
 * Copyright (c) 2012, Carlos D. Correa (info@ngraph.org)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of netzen nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************************/
#include <math.h>
#include <stdio.h>
#include <assert.h>

#include <algorithm>

#include "colormap.h"
#include "controller.h"
using namespace std;

ColorMap::ColorMap(int type) {
  this->type = type;
	controller = 0;
}

ColorMap::ColorMap(const char *n, int type) {
  name = string(n);
  this->type = type;
	controller = 0;
}

ColorMap::~ColorMap() {
  for(vector<ColorItem*>::iterator it  = colors.begin(); it != colors.end(); ++it) {
    delete (*it);
  }
}

void ColorMap::read(const char *file) {
  FILE *fp = fopen(file, "r");
  if(!fp) {
      string strFile2 = "";
      bool retry = controller->retryOpenFile(file, strFile2);
      if(!retry){
          return;
      }
      fp = fopen(strFile2.c_str(),"r");
  }

  float r, g, b;
  for(int i=0;i<sizeArray/3;i++) {
    fscanf(fp, "%f %f %f", &r, &g, &b);
    RGB[3*i+0] = r;
    RGB[3*i+1] = g;
    RGB[3*i+2] = b;
  }

  fclose(fp);
}

ColorItem * ColorMap::insert(float t, float r, float g, float b) {
  ColorItem* item = new ColorItem(t,r,g,b);
  colors.push_back(item);
  return item;
}

ColorItem * ColorMap::insert(int i, float r, float g, float b) {
  ColorItem* item = new ColorItem(0,r,g,b);
  colors.insert(colors.begin()+i, item);
  //printf("Set color size=[%d]\n", colors.size());
  return item;
}

void ColorMap::setColor(int i, float r, float g, float b) {
  int n = (int) colors.size();
  int bin = max(0,i);
  if(bin>=n) bin = bin%n;
  colors[bin]->r = r;
  colors[bin]->g = g;
  colors[bin]->b = b;
}

void ColorMap::getColor(float f, float *rgb) {
  int n = sizeArray/3;
  int bin = (int) (fmax(0,fmin(f,1))*n);
  if(bin>=n) bin = n-1;
  rgb[0] = RGB[3*bin+0];
  rgb[1] = RGB[3*bin+1];
  rgb[2] = RGB[3*bin+2];
  //printf("Get f %f bin %d :  %f %f %f\n", f, bin, rgb[0], rgb[1], rgb[2]);
}

void ColorMap::getColor(int i, float *rgb) {
  int n = (int) colors.size();
  int bin = max(0,i);
  if(bin>=n) bin = bin%n;
  rgb[0] = colors[bin]->r;
  rgb[1] = colors[bin]->g;
  rgb[2] = colors[bin]->b;
  //printf("Get colorint bin %d :  %f %f %f\n", bin, rgb[0], rgb[1], rgb[2]);
}

void ColorMap::generate() {
  float *array = RGB;

  for(int i=0;i<size;i++) {
    array[3*i+0] = -1;
    array[3*i+1] = -1;
    array[3*i+2] = -1;
  }
  float last[3];
  float first[3];
  first[0] = first[1] = first[2] = 0.0;
  last[0] = last[1] = last[2] = 0.0;

  int maxValue = 0;
  int minValue = size;
  for(unsigned int i=0;i<colors.size();i++) {
    int value = (int) (colors[i]->t* (float) size);
    value = min(value, size-1);
    array[3*value+0] = colors[i]->r;
    array[3*value+1] = colors[i]->g;
    array[3*value+2] = colors[i]->b;
    if(value>maxValue) {
      maxValue = value;
      last[0] = colors[i]->r;
      last[1] = colors[i]->g;
      last[2] = colors[i]->b;
    }
    if(value<minValue) {
      minValue = value;
      first[0] = colors[i]->r;
      first[1] = colors[i]->g;
      first[2] = colors[i]->b;
    }
  }
  int value = size-1;
  array[3*value+0] = last[0];
  array[3*value+1] = last[1];
  array[3*value+2] = last[2];
  array[3*0+0] = first[0];
  array[3*0+1] = first[1];
  array[3*0+2] = first[2];


  float r = 0, g = 0, b = 0;
  if(array[0]>=0) {
    r = array[0];
    g = array[1];
    b = array[2];
  }
  float rdst, gdst, bdst;
  for(int i=0;i<size;i++) {
    int end = i;

    for(int j=i;j<size;j++) {
      if(array[3*j+0]>=0)  {
	rdst = array[3*j+0];
	gdst = array[3*j+1];
	bdst = array[3*j+2];
	end = j;
	break;
      }
    }
    if(end==i) continue;
    float deltar = (rdst-r)/(float) (end-i);
    float deltag = (gdst-g)/(float) (end-i);
    float deltab = (bdst-b)/(float) (end-i);

    for(int j=i;j<end;j++) {
      array[3*j+0] = r;
      array[3*j+1] = g;
      array[3*j+2] = b;
      r+=deltar;
      g+=deltag;
      b+=deltab;
    }
    i = end;
    r = rdst;
    g = gdst;
    b = bdst;
  }
	//assert(controller);
	if(controller) controller->colorUpdated();
}

void ColorMap::fill(float r, float g, float b) {
  for(int i=0;i<sizeArray/3;i++) {
    RGB[3*i+0] = r;
    RGB[3*i+1] = g;
    RGB[3*i+2] = b;
  }
}
  
void ColorMap::deleteColor(ColorItem *n) {
  vector<ColorItem*>::iterator it  = find(colors.begin(), colors.end(), n);
  delete (*it);
  colors.erase(it);
}

void ColorMap::setController(Controller *c) {
	controller = c;
}
